home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / ada / adaed-1.11 / adaed-1 / Adaed-1.11.0a / adalex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-07  |  20.5 KB  |  778 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9.  
  10. /*            Lexical scanner for ADA 
  11.  
  12. One line of text at a time is read in using getline(). Tokens are scanned
  13. for, and gettok() returns one token at a time to the parser. What is actually
  14. returned is a pointer to a structure for the parse stack capable of holding
  15. the token. No initialization is needed, as it has all been done statically
  16. (before run time).
  17. */
  18.  
  19. /* define PDEBUG to get some debug trace output */
  20.  
  21. #include "adalex.h"
  22. #include "miscprots.h"
  23. #include "errsprots.h"
  24. #include "adalexprots.h"
  25.  
  26. static int getline();
  27. static struct prsstack *newtoken(int, int, int, int);
  28. static int isdecimal(char);
  29. static int ishex(char);
  30. static int isletterordigit(char);
  31. static int scanidorint(char *, int *, int *, int (*func)(char), int);
  32. static void scanexp(char *, int *, int *);
  33. static int scandec(char *, int *, int *, int (*func)(char));
  34. static void checkbased(char *, int *);
  35. static void convtoupper(char *);
  36. static void nlisthash(int, int *, int *);
  37. static int newnode(char *, int, int);
  38.  
  39. /* Global variables */
  40.  
  41. int lineno = 0;                    /* Current line number in adafile */
  42. int colno;                        /* Current column number in adafile */
  43.  
  44. char *data = (char *)source_buf[0];        /* Current line of ada program */
  45. char *line = (char *)source_buf[0];        /* Pointer to character within data array */
  46. /* These are initialized so that an end of line is indicated */
  47.  
  48. char *nonprintingmsg[] = {    /* Messages for non-printing characters */
  49.     "NUL (^@)",
  50.     "SOH (^A)",
  51.     "STX (^B)",
  52.     "ETX (^C)",
  53.     "EOT (^D)",
  54.     "ENQ (^E)",
  55.     "ACK (^F)",
  56.     "BEL (^G)",
  57.     "BS (^H)",
  58.     "HT (^I)",
  59.     "LF (^J)",
  60.     "VT (^K)",
  61.     "FF (^L)",
  62.     "CR (^M)",
  63.     "SO (^N)",
  64.     "SI (^O)",
  65.     "DLE (^P)",
  66.     "DC1 (^Q)",
  67.     "DC2 (^R)",
  68.     "DC3 (^S)",
  69.     "DC4 (^T)",
  70.     "NAK (^U)",
  71.     "SYN (^V)",
  72.     "ETB (^W)",
  73.     "CAN (^X)",
  74.     "EM (^Y)",
  75.     "SUB (^Z)",
  76.     "ESC",
  77.     "FS",
  78.     "GS",
  79.     "RS",
  80.     "US"};
  81. char source_buf[NUM_LINES][MAXLINE + 1] = { '\0' }; /* Source lines buffer */
  82. int src_index = -1;        /* Index into source lines buffer */
  83.  
  84.  
  85. /* Getline: Read a line into data, returning EOF on end of file.
  86.     ^J, ^K, ^L, ^M (10-13) are all interpreted as end of line. 
  87.     Line, lineno, and colno    are set as neeeded. */
  88.  
  89. /* Note: At present, the listing of the ada source file is done after
  90.    reading the line, in getline(). Because the source file may have tabs,
  91.    in order to insure that the relative spacing of the characters in the
  92.    source file appears correctly on the screen and that underlining of
  93.    errors occurs correctly, the number of characters printed on each
  94.    line before the next source line should be a multiple of 8 (tab stops
  95.    are at 8k+1). At present we leave 5 spaces for the line number, print
  96.    a colon (:), and leave 2 more spaces before printing the source line for
  97.    a total of 8 spaces.
  98. */
  99.  
  100. /* A buffer of NUM_LINES source lines is kept for the purpose of printing
  101.    error messages. Source_buf is the buffer, src_index is the index into
  102.    the buffer for the current line.
  103. */
  104.  
  105.  
  106. static int getline()                                            /*;getline*/
  107. {
  108.     int ch, ind = 0;
  109.  
  110.     if (feof(adafile))
  111.         return(EOF);
  112.     src_index = (src_index + 1) % NUM_LINES;
  113.     line = data = source_buf[src_index];
  114.     lineno++;
  115.     colno = 1;
  116.     for (;;) {
  117.         ch = getc(adafile);
  118.         if (ch==EOF) break;
  119.         if (ch <= 13 && ch >= 10) break;
  120.         if (ind == MAXLINE) {
  121.             char msg[80];
  122.             sprintf(msg,
  123.               "Line %d exceeds maximum length, truncated to %d characters",
  124.               lineno, MAXLINE);
  125.             lexerr(lineno, 1, 1, msg);
  126.             while ((ch = getc(adafile)) != EOF && !(ch<=13 && ch>=10));
  127.             break;
  128.         }
  129.         else {
  130.             data[ind++] = ch;
  131.         }
  132.     }
  133.  
  134.     data[ind] = '\0';
  135.     if (ch == EOF && !ind)
  136.         return(EOF);
  137. #ifdef DEBUG
  138.     if (trcopt)
  139.         fprintf(errfile, "%5d:    %s\n", lineno, data);
  140.     if (termopt)
  141.         printf(         "%5d:    %s\n", lineno, data);
  142. #endif    
  143.     return(0);
  144. }
  145.  
  146. static struct prsstack *newtoken(int num, int index, int line, int col)
  147.                                                                 /*;newtoken*/
  148. {
  149.     /* Newtoken: allocate memory for a new token structure, and initialize */
  150.     /* the fields of the structure. */
  151.  
  152.     struct prsstack *tok;
  153.  
  154.     tok = PRSALLOC();
  155.     tok->symbol = num;
  156.     tok->ptr.token = TOKALLOC();
  157.     tok->ptr.token->index = index;
  158.     tok->ptr.token->loc.line = line;
  159.     tok->ptr.token->loc.col = col;
  160.     return(tok);
  161. }
  162.  
  163. /* Functions for passing to scanidorint */
  164.  
  165. static int isdecimal(char ch)                                    /*;isdecimal*/
  166. {
  167.     return(isdigit(ch));
  168. }
  169.  
  170. static int ishex(char ch)                                        /*;ishex*/
  171. {
  172.     return(isdigit(ch) || 'A' <= ch && ch <= 'F' || 'a' <= ch && ch <= 'f');
  173. }
  174.  
  175. static int isletterordigit(char ch)                        /*;isletterordigit*/
  176. {
  177.     return(isalpha(ch) || isdigit(ch));
  178. }
  179.  
  180. struct prsstack *gettok()                                        /*;gettok*/
  181. {
  182.     /* Gettok: Scan and return the next token in the adafile, adding the */
  183.     /* token to namelist. */
  184.  
  185.     static int nextcanbeprime = 0;    /* The next token can be a prime */
  186.     static int canbeprime;            /* The current token can be a prime */
  187.     struct prsstack *tok;            /* Token to be returned */
  188.  
  189.     while (1) {
  190.         while (1) {
  191.             while (*line == ' ' || *line == '\t') {
  192.                 colno += (*line == '\t') ? (8 - ((colno - 1) % 8)) : 1;
  193.                 line++;
  194.             }
  195.             if (!*line || *line == '-' && line[1] == '-')
  196.                 break;
  197.             canbeprime = nextcanbeprime;
  198.             nextcanbeprime = 0;
  199.  
  200.             if (isalpha(*line)) {        /* Scan identifiers */
  201.                 char id[MAXLINE + 1];
  202.                 int idind = 0, chread = 0;
  203.                 int tokind, toksym;
  204.  
  205.                 scanidorint(id, &idind, &chread, isletterordigit, 0);
  206.                 if (id[idind - 1] == '_')
  207.                     idind--;
  208.                 id[idind] = '\0';
  209.                 convtoupper(id);
  210.                 tokind = namemap(id, idind);
  211.                 toksym = MIN(tokind, ID_SYM);
  212.                 tok = newtoken(toksym, tokind, lineno, colno);
  213.                 nextcanbeprime = toksym == ID_SYM || toksym == RANGE_SYM
  214.                   || toksym == ALL_SYM;
  215.                 colno += chread;
  216.                 line += chread;
  217.                 return(tok);
  218.             }
  219.  
  220.             else if (isdigit(*line) || *line == '.' && isdigit(line[1])) {
  221.             /* Scan numeric literals */
  222.                 char num[MAXLINE + 3];
  223.                 int ind = 0, chread = 0, result;
  224.                 char ch;
  225.                 /* ind is the index into the num string */
  226.                 /* chread is the index into the line input string */
  227.  
  228.                 result = scandec(num, &ind, &chread, isdecimal);
  229.                 ch = line[chread];
  230.                 if (result == 1 && (ch == '#' || ch == ':')) {
  231.                 /* Scan for the rest of a based literal */
  232.                     num[ind++] = '#';
  233.                     chread++;
  234.                     if (!scandec(num, &ind, &chread, ishex)) {
  235.                         lexerr(lineno, colno + chread - 1, colno + chread - 1,
  236.                           "Incomplete based number");
  237.                         num[ind++] = '0';
  238.                     }
  239.                     num[ind++] = '#';
  240.                     if (line[chread] != ch) {
  241.                         if (line[chread] == '#' + ':' - ch) {
  242.                             lexerr(lineno, colno + chread, colno + chread,
  243.                               "Expect #'s or :'s in based number to match");
  244.                             chread++;
  245.                         }
  246.                         else {
  247.                             char msg[50];
  248.  
  249.                             sprintf(msg, "Expect '%c' after last digit", ch);
  250.                             lexerr(lineno, colno + chread - 1,
  251.                               colno + chread - 1, msg);
  252.                         }
  253.                     }
  254.                     else
  255.                         chread++;
  256.                     checkbased(num, &ind);
  257.                 }
  258.                 scanexp(num, &ind, &chread);
  259.                 if (isalpha(line[chread]))
  260.                     lexerr(lineno, colno, colno + chread - 1,
  261.                       "Number should be separated from adjacent identifier");
  262.                 num[ind] = '\0';
  263.                 tok = newtoken(NUMBER_SYM, namemap(num, ind), lineno, colno);
  264.                 colno += chread;
  265.                 line += chread;
  266.                 return(tok);
  267.             }
  268.  
  269.             else if (*line == '\'') {
  270.                 int err = 0;
  271.  
  272.                 if (line[1] != '\0' && line[2] == '\'' &&
  273.                     (!canbeprime || line[1] != '(')) {
  274.                 /* Scan a character literal */
  275.                     char str[4];
  276.                     int len = 3;
  277.  
  278.                     strcpy(str, "' '");
  279.                     if (!isprint(line[1]) && line[1] != ' ') {
  280.                         char msg[80];
  281.  
  282.                         sprintf(msg,
  283.   "Invalid character %s in character literal replaced by space",
  284.                           nonprintingmsg[line[1]]);
  285.                         lexerr(lineno, colno + 1, colno + 1, msg);
  286.                         len = (line[1] == '\t') ? (10 - (colno % 8)) : 2;
  287.                     }
  288.                     else
  289.                         str[1] = line[1];
  290.                     tok = newtoken(CHAR_SYM, namemap(str, 3), lineno, colno);
  291.                     colno += len;
  292.                     line += 3;
  293.                     return(tok);
  294.                 }
  295.                 else if (!canbeprime) {
  296.                 /* Possibly a single quote delimited string */
  297.                     int ind;
  298.  
  299.                     if (line[1] == '\'')
  300.                         ind = 1;
  301.                     else {
  302.                         ind = 3;
  303.                         while (line[ind]) {
  304.                             if (line[ind] == '\'') {
  305.                                 if (line[ind + 1] && line[ind + 2] == '\'') {
  306.                                     ind = -1;
  307.                                     break;
  308.                                 }
  309.                                 else {
  310.                                     if (line[ind + 1] != '\'')
  311.                                         break;
  312.                                     ind++;
  313.                                 }
  314.                             }
  315.                             ind++;
  316.                         }
  317.                     }
  318.                     if (ind > -1 && line[ind]) {
  319.                         err = 1;
  320.                         lexerr(lineno, colno, colno + ind,
  321.                           "Expect double quotes to delimit a character string");
  322.                         do
  323.                             if (line[ind] == '\'')
  324.                                 line[ind] = '"';
  325.                         while (ind--);
  326.                     }
  327.                 }
  328.                 if (!err) {     /* A prime */
  329.                     int ind = namemap("'", 1);
  330.  
  331.                     tok = newtoken(ind, ind, lineno, colno);
  332.                     colno++;
  333.                     line++;
  334.                     return(tok);
  335.                 }
  336.             }
  337.             else if (*line == '"' || *line == '%') {
  338.             /* Scan a string literal */
  339.                 int col = colno;
  340.                 int oldindex = 0, newindex = -1;
  341.                 char bracket = *line;
  342.                 char nxtchr ;
  343.                 char tmpstr[MAXLINE + 1];
  344.                 int   save_col;       /* these are maintained to restore line */
  345.                 char *save_line;   /* in case of missing string bracket */
  346.                 int   save_newindex;
  347.  
  348.                 if ( (strchr(line+1, bracket)) == 0 ) {
  349.                     char bracket_str[2];
  350.                     *bracket_str = bracket; 
  351.                     *(bracket_str + 1) = '\0';
  352.                     tok = newtoken(ERROR_SYM, namemap(bracket_str, 1),
  353.                         lineno, colno);
  354.                     line++;
  355.                     colno++;
  356.                     return(tok);
  357.                 }
  358.                 while (1) {
  359.                     save_line = line + oldindex + 1;
  360.                     save_col = col + 1;
  361.                     save_newindex = newindex + 1;
  362.                     do {
  363.                         col++;
  364.                         oldindex++;
  365.                         newindex++;
  366.                         nxtchr = line[oldindex] ;
  367.                         tmpstr[newindex] = nxtchr ;
  368.                     }
  369.                     /* test separately for bracket for use of % as delimiter */
  370.                     while (nxtchr != bracket  && IS_STRING_CHAR(nxtchr));
  371.  
  372.                     if (line[oldindex] == bracket) {
  373.                         if (line[oldindex + 1] == bracket) {
  374.                             tmpstr[newindex] = bracket ;
  375.                             oldindex++;
  376.                             col++;
  377.                         }
  378.                         else {
  379.                             tmpstr[newindex] = '\0';
  380.                             tok = newtoken(STRING_SYM, namemap(tmpstr,
  381.                               newindex), lineno, colno+1);
  382.                             colno = col + 1;
  383.                             line += oldindex + 1;
  384.                             return(tok);
  385.                         }
  386.                     }
  387.                     else if (line[oldindex] == '"') {
  388.                         oldindex++;
  389.                         lexerr(lineno, col, col,
  390.                           "% delimited string contains \", being ignored");
  391.                     }
  392.                     else if (line[oldindex] == '\0') {
  393.                         lexerr(lineno, colno, colno, "Missing string bracket");
  394.                         /* restore values of line and colno to values prior to
  395.                          * last set of string characters 
  396.                           */
  397.                         line = save_line;
  398.                         colno = save_col;
  399.                         /*  insert a closing string bracket */
  400.                         tmpstr[save_newindex] = bracket;
  401.                         tmpstr[save_newindex + 1] = '\0';
  402.                         tok = newtoken(STRING_SYM, namemap(tmpstr,
  403.                           save_newindex + 1), lineno, colno);
  404.                         return(tok);
  405.                     }
  406. /*
  407.             else if (isprint(line[oldindex]) || line[oldindex] == ' ')
  408.             tmpstr[newindex] = line[oldindex];
  409. */
  410.                     else {
  411.                         char msg[80];
  412.  
  413.                         sprintf(msg, "Invalid character %s in string deleted",
  414.                           nonprintingmsg[line[oldindex++]]);
  415.                         lexerr(lineno, col, col, msg);
  416.                         col += (line[oldindex] == '\t') ? 7 - ((col-1)%8) : -1;
  417.                     }
  418.                 }
  419.             }
  420.  
  421.             else if (ISDELIMITER(*line))    /* Scan a delimiter */
  422.             {
  423.                 int len = 1, ind;
  424.                 char str[3];
  425.  
  426.                 switch (*line) {
  427.                 case '=' :
  428.                     if (line[1] == '>')
  429.                         len = 2;
  430.                     break;
  431.                 case '*' :
  432.                     if (line[1] == '*')
  433.                         len = 2;
  434.                     break;
  435.                 case ':' :
  436.                 case '/' :
  437.                     if (line[1] == '=')
  438.                         len = 2;
  439.                     break;
  440.                 case '>' :
  441.                     if (line[1] == '=' || line[1] == '>')
  442.                         len = 2;
  443.                     break;
  444.                 case '<' :
  445.                     if (line[1] == '=' || line[1] == '<' || line[1] == '>')
  446.                         len = 2;
  447.                     break;
  448.                 case '.' :
  449.                     if (line[1] == '.')
  450.                         len = 2;
  451.                     break;
  452.                 case '!' :
  453.                     *line = '|';
  454.                     break;
  455.                 case '[' :    /* Change to a "(" */
  456.                     lexerr(lineno, colno, colno,
  457.                       "Bad character \"[\", replaced by \"(\".") ;
  458.                     line[0] = '(' ;
  459.                     break ;
  460.                 case ']' :    /* Change to a ")" */
  461.                     /* Note that this case falls through to the next one */
  462.                     lexerr(lineno, colno, colno,
  463.                       "Bad character \"]\", replaced by \")\".") ;
  464.                     line[0] = ')' ;
  465.                 case ')' :
  466.                     nextcanbeprime = 1;
  467.                     break;
  468.                 }
  469.                 strncpy(str, line, len);
  470.                 str[len] = '\0';
  471.                 ind = namemap(str, len);
  472.                 tok = newtoken(ind, ind, lineno, colno);
  473.                 colno += len;
  474.                 line += len;
  475.                 return(tok);
  476.             }
  477.  
  478.             else if (*line == '_') {    /* An error- an underline _ */
  479.                 lexerr(lineno, colno, colno, "Break character misplaced");
  480.                 colno++;
  481.                 line++;
  482.             }
  483.  
  484.             else {    /* An error- an unknown character */
  485.                 char msg[80];
  486.                 char ch[2];
  487.  
  488.                 *ch = *line;
  489.                 ch[1] = '\0';
  490.                 sprintf(msg, "Bad character in file ignored: %s",
  491.                     (isprint(*line)) ? ch : nonprintingmsg[*line]);
  492.                 lexerr(lineno, colno, colno, msg);
  493.                 if (isprint(*line))
  494.                     colno++;
  495.                 line++;
  496.             }
  497.         }
  498.         if (getline() == EOF)
  499.             return(newtoken(EOFT_SYM, EOFT_SYM, lineno, colno));
  500.     }
  501. }
  502.  
  503. static int scanidorint(char *str, int *ind, int *chread, int (*func)(char),
  504.   int ignore_break)                                            /*;scanidorint*/
  505. {
  506.     /* Scanidorint: scan for an integer or id, with allowed characters
  507.      * determined by satisfying function func. 1 returned if found, 0 if not.
  508.      */
  509.     /* ind is the index into the string str,
  510.      * chread is the index into the input string line
  511.      * func is a function to be called to determine what chars are to
  512.      * be included in the integer or identifier
  513.      */
  514.  
  515.     int hadnum = 0;
  516.  
  517.     while (1) {
  518.         if (line[*chread] == '_') {
  519.             lexerr(lineno, colno + *chread, colno + *chread,
  520.               "Break character misplaced");
  521.             (*chread)++;
  522.             continue;
  523.         }
  524.         if (!(*func)(line[*chread])) {
  525.             if (hadnum)
  526.                 lexerr(lineno, colno + *chread - 1, colno + *chread - 1,
  527.                   "Break character misplaced");
  528.             break;
  529.         }
  530.         str[(*ind)++] = line[(*chread)++];
  531.         hadnum = 1;
  532.         while ((*func)(line[*chread]))
  533.             str[(*ind)++] = line[(*chread)++];
  534.         if (line[*chread] != '_')
  535.             break;
  536.         (*chread)++;
  537.         if (!ignore_break)
  538.             str[(*ind)++] = '_';
  539.     }
  540.     return(hadnum);
  541. }
  542.  
  543. static void scanexp(char *str, int *ind, int *chread)            /*;scanexp*/
  544. {
  545.     /* Scanexp: scan for an (optional) exponent
  546.      * ind is the index into the string str,
  547.      * chread is the index into the input string line
  548.      */
  549.  
  550.     int oldchread;
  551.  
  552.     if (line[*chread] != 'E' && line[*chread] != 'e')
  553.         return;
  554.     oldchread = *chread;
  555.     str[(*ind)++] = 'E';
  556.     *chread += 1;
  557.     if (line[*chread] == '+' || line[*chread] == '-')
  558.         str[(*ind)++] = line[(*chread)++];
  559.     if (!scanidorint(str, ind, chread, isdecimal, 1)) {
  560.         lexerr(lineno, colno + oldchread, colno + *chread - 1,
  561.           "Incomplete exponent");
  562.         str[(*ind)++] = '0';
  563.     }
  564. }
  565.  
  566. static int scandec(char *str, int *ind, int *chread, int (*func)(char))
  567.                                                                 /*;scandec*/
  568. {
  569.     /* Scandec: scan for an integer followed possibly by a decimal point and 
  570.      * another integer, with digits determined by satisfying func. 1 is returned
  571.      * if an integer is found, 2 if a there was a decimal point, 0 if no digits
  572.      * found.
  573.      * ind is the index into the string str,
  574.      * chread is the index into the input string line
  575.      * func is a func indicating valid characters for numbers being scanned
  576.      */
  577.  
  578.     int stat;
  579.  
  580.     stat = scanidorint(str, ind, chread, func, 1);
  581.     if (line[*chread] == '.') {
  582.         if (line[*chread + 1] != '.') {
  583.             if (!stat) {
  584.                 lexerr(lineno, colno + *chread, colno + *chread,
  585.                   "Missing digit before decimal point");
  586.                 str[(*ind)++] = '0';
  587.             }
  588.             str[(*ind)++] = '.';
  589.             (*chread)++;
  590.             if (!scanidorint(str, ind, chread, func, 1)) {
  591.                 lexerr(lineno, colno + *chread - 1, colno + *chread - 1,
  592.                   "Missing digit after decimal point");
  593.                 str[(*ind)++] = '0';
  594.             }
  595.             return(2);
  596.         }
  597.     }
  598.     return(stat);
  599. }
  600.  
  601. static void checkbased(char *str, int *ind)/*;checkbased*/
  602. {
  603.     /* Checkbased: check the validity of a based literal */
  604.  
  605.     int base, err = 0;
  606.     char *pos;
  607.  
  608.     sscanf(str, "%d", &base);
  609.     pos = strchr(str, '#');
  610.     if (base < 2 || base > 16) {
  611.         lexerr(lineno, colno, colno + pos - str - 1,
  612.           "Base not in range 2..16");
  613.         err = 1;
  614.     }
  615.     else 
  616.         while (*++pos != '#') {
  617.             if (islower(*pos))
  618.                 *pos = toupper(*pos);
  619.             if (isdigit(*pos) && *pos - '0' >= base
  620.               || isalpha(*pos) && *pos - 'A' >= base - 10) {
  621.                 lexerr(lineno, colno + pos - str, colno + pos - str,
  622.                   "Invalid based-number digit");
  623.                 err = 1;
  624.                 break;
  625.             }
  626.         }
  627.     if (err) {
  628.         if (strchr(str, '.') == (char *)0) {
  629.             *ind = 1;
  630.             *str = '0';
  631.         }
  632.         else {
  633.             *ind = 3;
  634.             strcpy(str, "0.0");
  635.         }
  636.     }
  637. }
  638.  
  639. static void convtoupper(char *s)                            /*;convtoupper*/
  640. {
  641.     /* Convtoupper: convert an entire string to uppercase. */
  642.  
  643.     while (*s) {
  644.         if (islower(*s))
  645.             *s = toupper(*s);
  646.         s++;
  647.     }
  648. }
  649.  
  650. /* merge below text formerly in namelist.c */
  651.  
  652. /* This file contains routines for dealing with namelist/namemap.
  653.    The setup of this map is as follows. We have two arrays: numtostrtable
  654.    and strtonumtable, which are used as hash tables for going from numbers
  655.    to strings and strings to numbers. The hash function from numbers to
  656.    strings is simply taking the number modulo the size of numtostrtable,
  657.    which gives us both the row of numtostrtable where the proper entry for
  658.    a given string should be found, and also where in this row it can be
  659.    found, eliminating the need for searching. The numbers representing the
  660.    strings are assigned sequentially, so we will always be adding a structure
  661.    into a row a the end of the list. This list is kept circularly so as
  662.    to be able to always find the beginning and end of the list quickly,
  663.    and not keep two pointers. When going from strings to numbers, we must
  664.    always search for the string, so the order of the strings in a given row
  665.    of strtonumtable does not matter. Each structure that is put into
  666.    these hash tables holds a string and the corresponding number, and two
  667.    pointers. One pointer points to the next structure in the row of
  668.    numtostrtable in which it lies, and the other points to the next structure
  669.    in the row of strtonumtable in which it lies. Each structure is in two
  670.    linked lists at once, one for each hash table. The grammar symbols and
  671.    predefined pragmas are statically initialized to be in these maps, with
  672.    all pointers set up properly.
  673. */
  674.  
  675. static void nlisthash(int num, int *row, int *links)            /*;nlisthash*/
  676. {
  677.     /* Nlisthash: Hashing function from numbers to strings */
  678.  
  679.     if (num <= 0) printf("nlisthash arg %d negative - chaos\n", num);
  680.     *links = (num - 1) / NAMELISTSIZE;
  681.     *row = (num - 1) % NAMELISTSIZE;
  682. }
  683.  
  684. static int newnode(char *str, int len, int nmhash)                /*;newnode*/
  685. {
  686.     /* Newnode: Allocate storage for a new node; set the fields; insert in 
  687.      * namelist and namemap. The symbol number is returned. Nmhash is either
  688.      * the hashvalue for the given string if already known, or -1 indicating
  689.      * not yet known.
  690.      */
  691.  
  692.     struct namelistmap *node;
  693.     int row, links;
  694.  
  695.     /* Allocate and set fields of node */
  696.     node = (struct namelistmap *)malloc(sizeof(struct namelistmap));
  697.     node->num = ++symcount;
  698.     node->name = malloc((unsigned)(len + 1));
  699.     strcpy(node->name, str);
  700.  
  701.     /* Insert in namelist */
  702.     nlisthash(symcount, &row, &links);
  703.     node->nextlist = numtostrtable[row]->nextlist;
  704.     numtostrtable[row]->nextlist = node;
  705.     numtostrtable[row] = node;
  706.  
  707.     /* Insert in namemap */
  708.     if (nmhash == -1)
  709.         nmhash = strhash(node->name) % NAMEMAPSIZE;
  710.     node->nextmap = strtonumtable[nmhash];
  711.     strtonumtable[nmhash] = node;
  712.  
  713.     return(symcount);
  714. }
  715.  
  716. char *namelist(int num)                                            /*;namelist*/
  717. {
  718.     /* Namelist: Given a symbol number return the corresponding string (the
  719.      * number is assumed to correspond to an entry known to be in the table
  720.      * already)
  721.      */
  722.  
  723.     int row, links;
  724.     struct namelistmap *node;
  725.  
  726.     nlisthash(num, &row, &links);
  727.     node = numtostrtable[row]->nextlist;
  728.     while (links--)
  729.         node = node->nextlist;
  730.     return(node->name);
  731. }
  732.  
  733. int namemap(char *str, int len)                                    /*;namemap*/
  734. {
  735.     /* Namemap: Give the symbol number corresponding to a given string, putting 
  736.      * the string into the structure if not already there. If the string is
  737.      * already known to be in the table, then it is not necessary to give the
  738.      * length.
  739.      */
  740.  
  741.     int nmhash;
  742.     struct namelistmap *node;
  743.     int nnode;
  744.  
  745. #ifdef PDEBUG
  746.     printf("namemap %s\n", str);
  747. #endif
  748.     nmhash = strhash(str) % NAMEMAPSIZE;
  749.     for (node = strtonumtable[nmhash]; node != (struct namelistmap *)0; 
  750.       node = node->nextmap) {
  751.         if (!strcmp(node->name, str)) {
  752. #ifdef PDEBUG
  753.             printf("namemap returns %d\n", node->num);
  754. #endif
  755.             return(node->num);
  756.         }
  757.     }
  758.     nnode = newnode(str, len, nmhash);
  759. #ifdef PDEBUG
  760.     printf("namemap returns (new) %d\n", nnode);
  761. #endif
  762.     return nnode;
  763. }
  764.  
  765. int name_map(char *str)                                            /*;name_map*/
  766. {
  767.     int nmhash;
  768.     struct namelistmap *node;
  769.  
  770.     nmhash = strhash(str) % NAMEMAPSIZE;
  771.     for (node = strtonumtable[nmhash]; node != (struct namelistmap *)0; 
  772.       node = node->nextmap) {
  773.         if (!strcmp(node->name, str))
  774.             return(1);
  775.     }
  776.     return(0);
  777. }
  778.